/*
 * Transparency.java    0.0.1    08/dic/2009
 * 
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */ 
package org.mentalsmash.tazio.transparency.interfaces;

import java.io.Serializable;

import org.mentalsmash.tazio.transparency.impl.TransparentDeliveryException;

/**
 * This interface is used to offer to the upper layers an uniform way to connect to the 
 * system and to send messages to remote recipients.
 * <p>
 * This interface is used on the WeakReplicaManager's side to avoid that the upper layers 
 * have to worry about connecting and sending messages to a ReplicaManager. Since the WRMs 
 * do not have the possibility to send group messages or messages addressed to other WRMs, 
 * their only recipients will be ReplicaManagers, one at a time.
 * Thus, using this interface, the WeakReplicaManager will simply have to use the method 
 * <code>connect()</code> to start working with the Tazio system, and then it will simply 
 * have to use one of the two methods used to send message, without worrying of specifying 
 * a recipient, it will all be managed by this layer, which will accomplish the task
 * of sending the messages to the correct recipient.
 * </p>
 * 
 * @version 0.0.1	08/dic/2009
 * @author Enrico Savioli <savioli.enrico@gmail.com>
 */
public interface Transparency {
	
	/**
	 * This method has to be invoked before the interaction with the Tazio system begins. 
	 * Calling this method the WeakReplicaManager initializes itself in order to be able to 
	 * register to the ReplicaManager and to correctly accomplish the interaction with the 
	 * ReplicaManagers.
	 */
	void connect();
	
	/**
	 * This method has to be invoked when a WeakReplicaManager wants to stop interacting 
	 * with the Tazio subsystem, by calling it the underlying running threads, communication 
	 * facades are stopped and the resources are freed, disallowing the resuming of the 
	 * collaboration.
	 */
	void disconnect();
	
	/**
	 * This method is used to send a Serializable object, or a subclass of it, to a 
	 * ReplicaManager contained in a list of server, continuing to send it to each of the 
	 * Replica Managers contained in the list until one of them answers to it. 
	 * <p>
	 * This method will have to encapsulate the message into a {@link TazioMessage} object 
	 * in order to grant the uniformity of messages delivered throughout the system. 
	 * </p>
	 * <p>
	 * This method will return the Serializable object contained in the {@link TazioMessage} 
	 * received as an answer to the message sent. 
	 * </p>
	 * 
	 * @param <T>
	 * @param message	the Serializable object that has to be encapsulated into a 
	 * 					{@link TazioMessage} and sent to a ReplicaManager.
	 * @return			the Serializable object contained in the answer to the message sent.
	 * @throws LocalException	thrown if the message has not been sent due to local problems.
	 * @throws TransparentDeliveryException  thrown if the message has not been sent due to network problems.
	 */
	<T extends Serializable> Serializable send(T message) throws TransparentDeliveryException;
	
	/**
	 * This method is used to send a Serializable object with an at-most-once behavior with 
	 * respect to a single ReplicaManager, which means that it will be sent only to the 
	 * Replica Manager this node is connected to, returning the answer to the sent message 
	 * or notifying an error in case the message could not be delivered. 
	 * <p>
	 * This method will have to encapsulate the message into a {@link TazioMessage} object 
	 * in order to grant the uniformity of messages delivered throughout the system. This 
	 * method will return the Serializable object contained in the {@link TazioMessage} 
	 * received as an answer to the message sent.
	 * </p>
	 * 
	 * @param <T>		a subclass of {@link Serializable}.
	 * @param message	the Serializable object that has to be encapsulated into a 
	 * 					{@link TazioMessage} and sent to a ReplicaManager.
	 * @return			the Serializable object contained in the answer to the message sent.
	 * @throws LocalException	thrown if the message has not been sent due to local problems.
	 * @throws TransparentDeliveryException	thrown if the message has not been sent due to network problems.
	 */
	<T extends Serializable> Serializable sendAtMostOnce(T message) throws TransparentDeliveryException;
	
	/**
	 * This method has to be invoked by a component interested in a specific type of message.
	 * <p>
	 * The {@link InputMessageListener} passed as a parameter will be added to the list of 
	 * listeners for the specified message type.
	 * </p>
	 * 
	 * @param <T>		a subclass of {@link Serializable}. 
	 * @param msgClass	the type of message the listener is interested into.
	 * @param listener	the {@link InputMessageListener listener} that will be notified when 
	 * 					a message of the specified type is received.
	 */
	void register(Class<? extends Serializable> msgClass, InputMessageListener listener);
	
	/**
	 * This method has to be invoked by a component that wants to be removed from the 
	 * listeners of a message.
	 * <p>
	 * The {@link InputMessageListener} passed as a parameter will be removed from the list 
	 * of listeners for the specified message type.
	 * </p>
	 * 
	 * 
	 * @param <T>		a subclass of {@link Serializable}.
	 * @param msgClass	the type of message the listener is no more interested into.
	 * @param listener	the {@link InputMessageListener listener} that will be removed from 
	 * 					the list of objects interested in messages of the specified type.
	 */
	void unregister(Class<? extends Serializable> msgClass, InputMessageListener listener);
	
}
